import * as Koa from 'koa';
import { pipe, cors } from './middleware';
import Router = require('koa-router');
import bodyParser = require("koa-bodyparser");
const convert = require('koa-convert');
import * as http from 'http';
import * as path from 'path';
import * as compress from 'koa-compress';
import * as logger from 'koa-logger';
import { RouteManager } from './common/http';
import { ServiceManager } from './common';
import { config, ServiceType } from './config';
import * as koaBody from 'koa-body';
import * as koaStaticPlus from 'koa-static-plus';

import { MessageService } from './service/messageService';
import { UserService } from './service/userService';
import { RoleService } from './service/roleService';
import { AccountService } from './service/accountService';
import { DepartmentService } from './service/departmentService';
import { OrganizationService } from './service/organizationService';
import { OrganizationTreeService } from './service/organizationTreeService';
import { AccountRolesService } from './service/accountRolesService';
import { FlowNodeService } from './service/flowNodeService';
import { PageService } from './service/pageService';
import { TemplateService } from './service/templateService';
import { AuthenService } from './service/authenService';
import { AccountPermitsService } from './service/AccountPermitsService';


export class Server {
    private router: Router;
    private app: Koa;
    private hostName: any = "0.0.0.0";

    constructor() {
        this.app = new Koa();
        this.router = new Router();
        this.init();
    }

    /**
     * 初始化方法
     * 顺序必须为:
     * (1)Parser
     * (2)MiddleWares
     * (3)Routers
     */
    private init() {
        this.registerService();
        this.registerParser();
        this.registerMiddleWares();
        this.registerRouters();
    }

    /**
     * http通信协议
     * (1)json
     * (2)form
     * (3)text
     */
    private registerParser() {
        this.app.use(koaBody(
            {
                multipart: true,
                formidable: {
                    // maxFileSize: 400 * 1024 * 1024    // 设置上传文件大小最大限制，默认2M
                }
            }
        ));
        this.app.use(bodyParser({
            extendTypes: {
                json: ['application/json'],
                form: ['application/x-www-form-urlencoded', 'multipart/form-data'],
                text: ['text/plain']
            },
            jsonLimit: "50mb",
            formLimit: "50mb",
            strict: false,
            onerror: (err: any, ctx) => {
                err.status = err.status || 422;
                err.body = err.body ? "请求数据有误！请求格式为：" + err.body : "请求数据有误！";
                let e = {
                    "code": err.status,
                    "msg": err.body
                };
                ctx.throw(JSON.stringify(e), err.status);
            }
        }));

        this.app.use(compress({
            filter: function (content_type) {
                return /json/i.test(content_type)
            },
            threshold: 2048 * 100,
            flush: require('zlib').Z_SYNC_FLUSH
        }));

        this.app.use(koaStaticPlus(path.join(__dirname, '../imageStore'), {
            pathPrefix: '/imageStore'
        }));

        // this.app.use(koaStaticPlus(path.join(__dirname, '../mp'), {
        //     pathPrefix: '/mp'
        // }));

        // this.app.use(koaStaticPlus(path.join(__dirname, '../grayscale_package_files'), {
        //     pathPrefix: '/grayscale_package_files'
        // }));

        // this.app.use(koaStaticPlus(path.join(__dirname, '../moduleFiles'), {
        //     pathPrefix: '/moduleFiles'
        // }));
    }

    /**
     * 挂载中间件
     * cors：跨域
     * pipe：异常处理
     * logger：日志 , logger()
     */
    private registerMiddleWares() {
        this.app.use(convert.compose(
            cors(),
            pipe(),
            logger()
        ));
    }

    /**
     * 挂载路由
     */
    private registerRouters() {
        require('./controller/index');
        let that = this;
        RouteManager.Current.Routes.forEach((controller, config) => {
            let controllers = Array.isArray(controller) ? controller : [controller];
            controllers.forEach(controller =>
                that.router[config.method.toLocaleLowerCase()](config.path, async function (ctx, next) {
                    if (config.verify) {
                        if (config.verify.NeedVerifyToken) {
                            await config.verify.TokenVerify(ctx, next);
                        }
                    }
                    await controller(ctx, next);
                })
            );
        });


        this.app.use(this.router.routes());
        this.app.use(this.router.allowedMethods());

    }

    private registerService() {
        if (config.type.find(x => x === ServiceType.API)) {
            ServiceManager.Current.RegistService([
                { serviceName: 'AuthenService', service: new AuthenService() },
                // { serviceName: 'AlipayService', service: new AlipayService() },
                // { serviceName: 'AliOSS', service: new AliOSS() },
                // { serviceName: 'AliSMSService', service: new AliSMSService() }
                { serviceName: 'UserService', service: new UserService() },
                { serviceName: 'RoleService', service: new RoleService() },
                { serviceName: 'AccountService', service: new AccountService() },
                { serviceName: 'DepartmentService', service: new DepartmentService() },
                { serviceName: 'OrganizationService', service: new OrganizationService() },
                { serviceName: 'OrganizationTreeService', service: new OrganizationTreeService() },
                { serviceName: 'AccountRolesService', service: new AccountRolesService() },
                { serviceName: 'AccountPermitsService', service: new AccountPermitsService() },
                { serviceName: 'FlowNodeService', service: new FlowNodeService() },
                { serviceName: 'PageService', service: new PageService() },
                { serviceName: 'TemplateService', service: new TemplateService() }


            ]);
        }
    }

    /**
     * 启动服务
     * 默认端口：8886
     */
    listen() {
        let maxListeners = Math.max(this.app.getMaxListeners() - 1, 0);
        this.app.setMaxListeners(maxListeners);
        console.log("事件监听数为：", maxListeners);

        // 监听 http
        let port = process.env.port || 80;
        this.app.listen(port, this.hostName, () => {
            console.log(`http 服务器启动成功，监听端口： ${port}, in ${this.app.env} mode`);
        });

        const msgSvr = ServiceManager.Current.GetService<MessageService>('MessageService');
        if (msgSvr) {
            let httpSvr = http.createServer(this.app.callback);
            let socketPort = process.env.socketPort || 3002;
            httpSvr.listen(socketPort);
            msgSvr.Start(httpSvr);
        }
    }
}